package main

import (
	"fmt"
	"time"
)

// main
//
//		@Description: 主线程需要writeData和readData协程执行完了才能退出
//	  在for...range遍历时，如果没有关闭channel，会出现deadlock的错误
func main() {
	//testPutAndGetData()
	testDeadLock()
}

// testPutAndGetData
//
//		@Description: 一个协程写数据，一个携程读取数据
//	 如果编译器发现一个管道只有写，而没有读 则该管道会阻塞
//	 如果写管道和读管道的频率不一致，无所谓
func testPutAndGetData() {
	//数据channel
	var dataChannel chan int = make(chan int, 50)
	//是否结束的channel
	var exitChannel chan bool = make(chan bool, 1)

	go writeData(dataChannel)
	go readData(dataChannel, exitChannel)

	<-exitChannel
	fmt.Printf("主函数退出~~~~")

}

// testDeadLock
//
//	@Description: 管道的容量 < 要放入的元素个数 ，发生deadlock
func testDeadLock() {

	//数据channel
	dataChannel := make(chan int, 10)
	//是否结束的channel
	exitChannel := make(chan bool, 1)

	go writeData(dataChannel)
	//go readData(dataChannel, exitChannel) // 发生阻塞...fatal error: all goroutines are asleep - deadlock!

	//方式一：直到读取到一个元素
	<-exitChannel
	fmt.Printf("主函数退出~~~~")

}

// writeData
//
//	@Description: 放入数据
//	@param dataChannel
func writeData(dataChannel chan int) {
	//写数据
	for i := 1; i <= 50; i++ {
		time.Sleep(time.Millisecond * 10)
		fmt.Println(">>>>>写入数据", i)
		dataChannel <- i
	}
	//关闭channel
	close(dataChannel)
}

// readData
//
//	@Description: 读取数据
//	@param dataChannel
//	@param exitChannel
func readData(dataChannel chan int, exitChannel chan bool) {
	for {
		v, ok := <-dataChannel
		if !ok {
			break
		}
		//time.Sleep(time.Millisecond * 100) //如果读取的速度 较慢，无问题！
		fmt.Println("读取到数据=", v)
	}
	//读取完数据的标识
	exitChannel <- true
	//关闭channel
	close(exitChannel)
}
